﻿using System;
using System.Collections.Generic;

namespace ZoeEngine.Framework
{
    public class ComponentCollection : ICollection<EntityComponent>
    {
        private bool _isReadOnly;
        private Dictionary<Type, EntityComponent> _allComponents = new Dictionary<Type, EntityComponent>();

        public T Find<T>() where T : EntityComponent
        {
            if (typeof(T).IsAbstract)
            {
                foreach (Type typeKey in _allComponents.Keys)
                {
                    if (typeof(T).IsAssignableFrom(typeKey))
                        return _allComponents[typeKey] as T;
                }
            }

            if (_allComponents.ContainsKey(typeof(T)))
            {
                return _allComponents[typeof(T)] as T;
            }

            return null;
        }
        public bool RemoveImmediate(EntityComponent item)
        {
            // Immediately remove component from this collection.
            bool result = _allComponents.Remove(item.GetType());

            // Tell the current component manager to also remove this component.
            item.Owner.Manager.RemoveImmediate(item);

            // Notify any registered objects that the component has been removed.
            OnComponentRemoved(new ComponentEventArgs(item));

            return result;
        }
        public bool Contains(Type t)
        {
            if (t.IsInterface)
            {
                foreach (Type typeKey in _allComponents.Keys)
                {
                    if (t.IsAssignableFrom(typeKey))
                        return true;
                }
                return false;
            }
            else if (t.IsAbstract)
            {
                foreach (Type typeKey in _allComponents.Keys)
                {
                    if (t.IsAssignableFrom(typeKey))
                        return true;
                }
                return false;
            }
            return _allComponents.ContainsKey(t);
        }

        public event EventHandler<ComponentEventArgs> ComponentAdded;
        public event EventHandler<ComponentEventArgs> ComponentRemoved;
        protected virtual void OnComponentAdded(ComponentEventArgs e)
        {
            if (ComponentAdded != null)
            {
                ComponentAdded(this, e);
            }
        }
        protected virtual void OnComponentRemoved(ComponentEventArgs e)
        {
            if (ComponentRemoved != null)
            {
                ComponentRemoved(this, e);
            }
        }

        public void Add(EntityComponent item)
        {
            if (_allComponents.ContainsKey(item.GetType()))
            {
                throw new ArgumentException("Cannot add component of duplicate type.");
            }
            else
            {
                _allComponents.Add(item.GetType(), item);
            }

            OnComponentAdded(new ComponentEventArgs(item));
            item.Initialize();

            if (item is IDrawn)
            {
                (item as IDrawn).LoadContent();
            }
        }
        public void Clear()
        {
            foreach (EntityComponent component in this)
            {
                component.Owner.Remove(component);
            }
        }
        public bool Contains(EntityComponent item)
        {
            return _allComponents.ContainsValue(item);
        }
        public void CopyTo(EntityComponent[] array, int arrayIndex)
        {
            _allComponents.Values.CopyTo(array, arrayIndex);
        }
        public bool Remove(EntityComponent item)
        {
            if (_allComponents.ContainsValue(item))
            {
                OnComponentRemoved(new ComponentEventArgs(item));
            }
            return false;
        }
        public IEnumerator<EntityComponent> GetEnumerator()
        {
            return _allComponents.Values.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _allComponents.Values.GetEnumerator();
        }

        public int Count
        {
            get
            {
                return _allComponents.Count;
            }
        }
        public bool IsReadOnly
        {
            get
            {
                return _isReadOnly;
            }
        }
    }
}
